﻿using System;
using System.Collections.Generic;
using System.Data.Objects.DataClasses;
using System.Linq;
using System.Text;

using Microsoft.Practices.EnterpriseLibrary.Validation;

using Arquitetura.Architectural.Model;

namespace Arquitetura.Architectural.BusinessLogic
{
    public abstract class Validation<T, O> : IValidation<T, O>
    {
        #region Propriedade(s)
        protected O Operacao
        { get; set; }

        protected T Target
        { get; set; }

        protected Resultado Resultado
        { get; set; }
        #endregion Propriedade(s)

        #region Construtor(es)
        public Validation(T target, O operacao)
        {
            Target = target;
            Operacao = operacao;
            Resultado = new Resultado();
        }
        #endregion Construtor(es)

        #region Método(s)
        private void ValidarDados()
        {
            ValidateBaseType(Target, typeof(T).BaseType);
            Validator<T> validator = ValidationFactory.CreateValidator<T>(Operacao.ToString());
            ValidationResults validationResults = validator.Validate(Target);
            Resultado.Sucesso &= validationResults.IsValid;
            Resultado.ConsolidarResultadosValidacao(validationResults);
        }

        private void ValidateBaseType(T Target, Type baseType)
        {
            if ((baseType != typeof(object)) &&      //Tipos Sem Persistencia (POCOS)
               (baseType != typeof(EntityObject)))  //Tipo Com Persistencia (EntityFramework)
            {
                ValidateBaseType(Target, baseType.BaseType);
                Validator validator = ValidationFactory.CreateValidator(baseType, Operacao.ToString());
                ValidationResults validationResults = validator.Validate(Target);
                Resultado.Sucesso &= validationResults.IsValid;
                Resultado.ConsolidarResultadosValidacao(validationResults);
            }
        }

        protected virtual void ValidarDadosAdicionais() { }

        protected virtual void ValidarRegras() { }

        public Resultado Validar()
        {
            LimparResultado();
            ValidarDados();
            ValidarDadosAdicionais();
            ValidarRegras();
            return new Resultado(Resultado);
        }

        protected void AdicionarResultado(Resultado resultado)
        {
            Resultado.Sucesso &= resultado.Sucesso;
            Resultado.Mensagens.AddRange(resultado.Mensagens);
        }

        protected void AdicionarResultado(bool sucesso, Mensagem mensagem)
        {
            if (mensagem == null)
                throw new ArgumentNullException("A mensagem de erros de validação não pode ser nula");

            Resultado.Sucesso &= sucesso;
            Resultado.Mensagens.Add(mensagem);
        }

        private void LimparResultado()
        {
            Resultado.Sucesso = true;
            Resultado.Mensagens.Clear();
        } 
        #endregion Método(s)
    }
}
